#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

#include <poll.h>
#include <fcntl.h>
#include <pthread.h>
#include <errno.h>
#include <assert.h>

#define USER_LIMIT 5
#define BUFF_SIZE 64
int user_count=0;
int user_clnt[USER_LIMIT]; 	//连接套接字保存其中
pthread_mutex_t mutx;

// int setnonblocking(int fd){
// 	int old_option = fcntl(fd, F_GETFL);
// 	int new_option = old_option|O_NONBLOCK;
// 	fcntl(fd, F_SETFL, new_option);
// 	return old_option;
// }
void send_msg(char* msg, int len){
	int i;
	pthread_mutex_lock(&mutx);
	for(i=0;i<user_count;i++)
		send(user_clnt[i], msg, len, 0);
	pthread_mutex_unlock(&mutx);
}

void* worker(void* arg){
	int connfd = *((int*)arg);
	char buf[BUFF_SIZE];
	int str_len, i;

	while(1){
		str_len = recv(connfd, buf, BUFF_SIZE-1, 0);
		if(str_len<0){
			if(errno == EAGAIN)
				break; // no more data
			else
				{printf("read erro?"); break;}
		}
		else if(str_len==0){
			// client data has closed connection
			break;
		}
		else{
			// send(connfd, buf, str_len, 0);
			send_msg(buf, str_len);
		}
	}
	// 切断连接
	pthread_mutex_lock(&mutx);
	for(i=0; i<user_count;i++){
		if(user_clnt[i]==connfd){
			while(i<user_count){
				user_clnt[i]=user_clnt[i+1];
				i++;
			}
			break;
		}
	}
	user_count--;
	pthread_mutex_unlock(&mutx);
	close(connfd);
	return NULL;
}	

int main(int argc, char const *argv[])
{
	const char* ip = "0.0.0.0";
	char* port = "9876";
	pthread_t tid;

	struct sockaddr_in address;
	bzero(&address, sizeof(address));
	address.sin_family = PF_INET;
	address.sin_addr.s_addr = inet_addr(ip);
	address.sin_port = htons(atoi(port));

	pthread_mutex_init(&mutx, NULL);

	int listenfd = socket(PF_INET, SOCK_STREAM, 0);
	assert(listenfd>=0);

	int ret = bind(listenfd, (struct sockaddr*)&address, sizeof(address));
	assert(ret!=-1);

	ret = listen(listenfd, 5);
	assert(ret!=-1);

	struct sockaddr_in cln_addr;
	socklen_t cln_addr_size = sizeof(cln_addr);
	while(1){
		int connfd = accept(listenfd, (struct sockaddr*)&cln_addr, &cln_addr_size);
		printf("connect client IP:%s \n",inet_ntoa(cln_addr.sin_addr));
		pthread_mutex_lock(&mutx);
		user_clnt[user_count] = connfd;
		user_count+=1;
		pthread_mutex_unlock(&mutx);
		pthread_create(&tid, NULL, worker, (void*)&connfd); //worker负责回声
		pthread_detach(tid);
	}
	return 0;
}